#include "llcomp_llc.h"
#include <stdlib.h>
;
#include <math.h>
;
#include <sys/times.h>
;
typedef  struct timeval  CLOCK_TYPE;
 double CLOCK_Avg(  double t) ;
 double CLOCK_Min(  double t) ;
 double CLOCK_Max(  double t) ;
  int *despl;
  int *count;
 double jacobi_mpi(  int miid,  double **a,  int nfilas,  int n,  double *b,  double *x,  double tol,  int maxit) 
{

      int   i;
      int   j;
      int   it = 0;
      double   sum;
      double   resi_local;
      double   resi;
      double   *  new_x;
      int   fin;
resi= 10.0;
new_x= (double *)(malloc((n * (sizeof( double ) )) ) );
  for (i= 0; (i < n); (i++ )) x[i]= b[i] ;
  while ((it < maxit))
{

fin= (despl[miid] + count[miid]);
resi_local= 0.0;
  for (i= despl[miid]; (i < fin); (i++ ))  
{

sum= 0.0;
    for (j= 0; (j < n); (j++ )) sum+= (a[i][j] * x[j]) ;
resi_local+= fabs((sum - b[i]) ) ;
sum+= ((-a[i][i] ) * x[i]);
new_x[i]= (((b[i] - sum)) / a[i][i]);
  }

 ;
MPI_Allgatherv  ((&new_x[despl[miid]] ),count[miid],MPI_DOUBLE,x,count,despl,MPI_DOUBLE,MPI_COMM_WORLD   ) ;
MPI_Allreduce  ((&resi_local ),(&resi ),1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD   ) ;
  (it++   );
}

;
free  (new_x   ) ;
  return resi;
}

;
 int llc_main(  int argc,  char *argv[]) 
{

      double   tol;
      double *  *  a;
      double   *  b;
      double   *  x;
      int   i;
      int   j;
      int   n;
      int   nfilas;
      int   diag;
      int   maxit;
      int   nprocs;
      int   miid;
      CLOCK_TYPE   chrono;
      double   mpi_time;
      double   mpi_resi;
nprocs= LLC_NUMPROCESSORS;
miid= LLC_NAME;
n= 200;
maxit= 500;
tol= 0.0000001;
  switch (argc)
{

  case 4 : tol= atof(argv[3] ) ;
  case 3 : maxit= atoi(argv[2] ) ;
  case 2 : n= atoi(argv[1] ) ;
}

;
nfilas= (n / nprocs);
ReservaMatriz  ((&a ),n,n   ) ;
ReservaVector  ((&b ),n   ) ;
ReservaVector  ((&x ),n   ) ;
  if   (  (miid == 0  )  )   
{

GeneraVector    (b,n     ) ;
  }

;
MPI_Bcast  (b,n,MPI_DOUBLE,0,MPI_COMM_WORLD   ) ;
  if   (  (miid == 0  )  )   
{

GeneraMatriz    (a,n,n     ) ;
diag= 0;
    for (i= 0; (i < n); (i++ ))    
{

      for (j= 0; (j < n); (j++ )) a[i][diag]+= a[i][j] ;
      (diag++       );
    }

 ;
  }

;
  for (i= 0; (i < n); (i++ )) MPI_Bcast  (a[i],n,MPI_DOUBLE,0,MPI_COMM_WORLD   )  ;
MPI_Barrier  (MPI_COMM_WORLD   ) ;
despl= (int *)(malloc((nprocs * (sizeof( int ) )) ) );
count= (int *)(malloc((nprocs * (sizeof( int ) )) ) );
despl[0]= 0;
  for (i= 0; (i < nprocs); (i++ ))  
{

count[i]= nfilas;
    if     (    i    ) despl[i]= (despl[(i - 1)] + count[(i - 1)])    ;;
  }

 ;
MPI_Barrier  (MPI_COMM_WORLD   ) ;
gettimeofday  ((&chrono ),NULL   ) ;
mpi_resi= jacobi_mpi(miid,a,nfilas,n,b,x,tol,maxit ) ;
  
{

          CLOCK_TYPE     ch2;
gettimeofday    ((&ch2 ),NULL     ) ;
mpi_time= ((double )((ch2.tv_sec  - chrono.tv_sec )) + (((double )((ch2.tv_usec  - chrono.tv_usec )) / 1.0e6)));
  }

;
MPI_Barrier  (MPI_COMM_WORLD   ) ;
printf  ("%d:%g:%g\n",LLC_NAME,mpi_time,mpi_resi   ) ;
LiberaMatriz  (a   ) ;
LiberaVector  (b   ) ;
LiberaVector  (x   ) ;
  return 0;
}

;
 int main(  int argc,  char **argv) 
{

      int   llc_return_code = 0;
MPI_Init  ((&argc ),(&argv )   ) ;
MPI_Comm_rank  (MPI_COMM_WORLD,(int *)((&LLC_GLOBAL_NAME ))   ) ;
MPI_Comm_size  (MPI_COMM_WORLD,(int *)((&LLC_GLOBAL_NUMPROCESSORS ))   ) ;
LLC_NAME= LLC_GLOBAL_NAME;
LLC_NUMPROCESSORS= LLC_GLOBAL_NUMPROCESSORS;
llc_GlobalGroup= MPI_COMM_WORLD;
llc_CurrentGroup= (&llc_GlobalGroup );
llc_return_code= llc_main(argc,argv ) ;
MPI_Finalize  (   ) ;
  return llc_return_code;
}

;
